package model

import (
	"errors"
	"fmt"
	"github.com/chicken-team-outside/chicken_transmission/proxy_server/setting"
	"github.com/chicken-team-outside/chicken_transmission/proxy_server/utils"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"time"
)

type UserStatus int8

const (
	ActiveStatue      = UserStatus(1)
	DisabledStatue    = UserStatus(2)
	NotVerifiedStatue = UserStatus(3)
)

func (s UserStatus) String() string {
	switch s {
	case ActiveStatue:
		return "active"
	case DisabledStatue:
		return "disabled"
	case NotVerifiedStatue:
		return "not verified"
	default:
		return fmt.Sprintf("unknown UserStatus: %d", s)
	}
}

type User struct {
	Id        uint64     `gorm:"colum:id;primaryKey;autoIncrement"`
	User      string     `gorm:"colum:user;type:varchar(255);uniqueIndex"`
	IsAdmin   bool       `gorm:"colum:is_admin"`
	Passwd    string     `gorm:"colum:passwd;not null"`
	Status    UserStatus `gorm:"colum:is_active"`
	Email     string     `gorm:"colum:email;not null"`
	Phone     string     `gorm:"colum:phone"`
	CreatedAt time.Time  `gorm:"colum:created_at;autoCreateTime"`
	UpdatedAt time.Time  `gorm:"colum:updated_at;autoUpdateTime"`
}

func (u User) TableName() string {
	return "User"
}

func (u User) CheckPassword(password string) bool {
	return utils.ComparePwd(u.Passwd, password)
}

func ExistsUser(username string) bool {
	var c int64
	setting.Db.Model(&User{}).Where("user = ?", username).Limit(1).Count(&c)
	return c > 0
}

func ExistsEmail(email string) bool {
	var c int64
	err := setting.Db.Model(&User{}).Where("email = ?", email).Limit(1).Count(&c).Error
	if err != nil {
		zap.L().Error("failed to check email exist", zap.Error(err), zap.String("email", email))
	}
	return c > 0
}

func AddUser(user *User) error {
	passwd, err := utils.GetPwd(user.Passwd)
	if err != nil {
		return err
	}
	user.Status = ActiveStatue
	user.Passwd = string(passwd)
	err = setting.Db.Create(user).Error
	if err != nil {
		return err
	}
	return nil
}

func UpdateUserPassword(email string, password string) error {
	pwd, err := utils.GetPwd(password)
	if err != nil {
		return err
	}
	return setting.Db.Model(&User{}).Where("email = ?", email).Update("passwd", string(pwd)).Error
}

func GetUserIdByEmail(email string) (uint64, error) {
	user := &User{}
	err := setting.Db.Where("email = ?", email).Limit(1).First(user).Error
	if err != nil {
		return 0, err
	}
	return user.Id, nil
}

func GetUserInfoByEmail(key string) (*User, error) {
	user := &User{}
	err := setting.Db.Where("email = ?", key).Limit(1).First(user).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return user, nil
}

func GetUserInfoById(id uint64) (*User, error) {
	user := &User{}
	err := setting.Db.Where("id = ?", id).Limit(1).First(user).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return user, nil
}
